package com.cqw.service;

import com.cqw.auth.service.TokenService;
import com.cqw.constant.Constants;
import com.cqw.domain.SysUser;
import com.cqw.enums.UserStateEnum;
import com.cqw.exception.CommonException;
import com.cqw.mapper.one.SysUserMapper;
import com.cqw.vo.LoginVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: caoqingwen
 * @CreateTime: 2021-07-16 17:46
 * @Description:
 */
@Service
public class SysLoginService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Value("${login.size}")
    private Integer loginSize;

    @Value("${login.out}")
    private Boolean loginOut;

    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    /**
     * 登录
     *
     * @param loginVO
     * @return
     */
    public String login(LoginVO loginVO) {
        String userName = loginVO.getUserName();
        String password = loginVO.getPassword();
        // 用户验证
        Authentication authentication = null;
        String loginSizeKey = Constants.LOGIN_SIZE_KEY + userName;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(userName, password));
        } catch (Exception e) {
            if (e instanceof InternalAuthenticationServiceException) {
                throw new CommonException(e.getMessage());
            }
            //发生异常，计算次数
            Integer num = (Integer) redisTemplate.opsForValue().get(loginSizeKey);
            int newNum = num == null ? 1 : num + 1;
            if (newNum < loginSize) {
                redisTemplate.opsForValue().set(loginSizeKey, newNum, 30, TimeUnit.DAYS);
                throw new CommonException("用户名或密码错误，还有【" + (loginSize - newNum) + "】次机会！");
            }

            //禁用账号
            sysUserMapper.updateStateByUserName(UserStateEnum.DISABLE.getCode(), userName);
            throw new CommonException("您的账号已锁定，请联系管理员解锁!");
        }
        SysUser loginUser = (SysUser) authentication.getPrincipal();
        //生成token
        Map<String, String> token = tokenService.createToken(loginUser);

        //踢人
        String loginOutKey = Constants.LOGIN_OUT_KEY + userName;
        String uuid = (String) redisTemplate.opsForValue().get(loginOutKey);

        if (StringUtils.isNotBlank(uuid)) {
            if (loginOut) {
                //不允许登录
                throw new CommonException("当前账号已登录，请确认！");
            }

            //踢掉前面的人
            String tokenKey = tokenService.getTokenKey(uuid);
            redisTemplate.delete(tokenKey);
        }
        redisTemplate.opsForValue().set(loginOutKey, token.get("uuid"), expireTime, TimeUnit.MINUTES);
        //登录成功，删除次数限制
        redisTemplate.delete(loginSizeKey);
        return token.get("token");
    }
}
